“我装了防火墙,密码也设得很复杂,怎么还是被入侵了?”——这是很多运维人员的困惑。实际上,Linux系统的安全是“纵深防御”,仅靠一个密码或一道防火墙远远不够。一个合格的生产环境,至少需要做到:网络层过滤(防火墙)、进程层强制访问控制(SELinux)、用户层最小权限(sudo)、文件层完整性校验(AIDE)、行为层审计(auditd)和攻击层阻断(Fail2ban)。
以RHEL 9.4、Rocky Linux 9和AlmaLinux 9等2026年主流企业级发行版为例,从实战角度讲解如何一步步加固Linux系统。所有命令均在生产环境验证,建议按顺序执行。
firewalld是RHEL 7+默认的动态防火墙管理器,支持运行时区和规则的动态修改,无需重启服务,且规则持久化。它比iptables更适合生产环境。
首先确认firewalld已安装并启动:
bash
systemctl enable firewalld --now systemctl status firewalld
查看当前默认区域(通常是public):
bash
firewall-cmd --get-default-zone
实战原则:默认拒绝一切,按需开放端口。
bash
# 设置默认区域为public,并禁止所有入站流量(保留ssh已允许) firewall-cmd --set-default-zone=public firewall-cmd --zone=public --remove-service=ssh # 先移除默认允许的ssh,后面再单独加
bash
# 允许SSH(建议更改端口号前先允许新端口) firewall-cmd --zone=public --add-port=22/tcp --permanent # 允许HTTP/HTTPS firewall-cmd --zone=public --add-service=http --add-service=https --permanent # 如果运行了数据库(如MySQL,建议只允许内网访问,此处示例仅允许特定IP) firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="3306" accept' --permanent
重要:永远不要直接开放数据库端口到公网。
bash
# 仅允许公司IP段访问22端口 firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="203.0.113.0/24" port protocol="tcp" port="22" accept' --permanent
bash
# 限制单个IP的连接数(防止DoS,需使用direct接口) firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -m state --state NEW -m recent --set firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
重载使生效:
bash
firewall-cmd --reload
查看当前规则:
bash
firewall-cmd --list-all
很多管理员一见到SELinux就“setenforce 0”关掉,这是极大的安全隐患。SELinux(Security-Enhanced Linux)是内核级强制访问控制,即使进程以root运行,也无法违反策略。生产环境建议保持Enforcing模式。
bash
getenforce # 显示Enforcing、Permissive或Disabled
若当前为Permissive(只记录不阻断),改为Enforcing:
bash
setenforce 1 sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
假设Nginx需要绑定非标准端口(如8080),SELinux会阻止。解决方法:
bash
# 查看SELinux允许的http端口 semanage port -l | grep http # 添加8080到http_port_t semanage port -a -t http_port_t -p tcp 8080
当移动网站目录后,Nginx可能因SELinux无法读取文件。恢复上下文:
bash
restorecon -Rv /var/www/html/
若需永久修改上下文:
bash
semanage fcontext -a -t httpd_sys_content_t "/newpath(/.*)?" restorecon -Rv /newpath
某些服务需要特定布尔值,比如httpd允许访问网络:
bash
setsebool -P httpd_can_network_connect on
当服务被SELinux阻断时,查看/var/log/audit/audit.log,使用:
bash
audit2why < /var/log/audit/audit.log
它会给出友好的解决方案建议。
bash
# 创建普通用户并设置密码 useradd deploy passwd deploy # 禁止root SSH登录 echo "PermitRootLogin no" >> /etc/ssh/sshd_config systemctl restart sshd
原则:用户只能执行必要的命令,而不是ALL。
编辑/etc/sudoers(使用visudo):
bash
visudo
示例:允许deploy用户重启nginx和查看日志,但不能做其他操作:
text
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/journalctl -u nginx -n 50
bash
passwd -l games passwd -l nobody # 注意:某些服务依赖nobody,谨慎锁定
bash
# 生成密钥对(客户端) ssh-keygen -t ed25519 -C "deploy@your-server" # 将公钥上传到服务器 ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@server_ip # 服务器上禁用密码登录 echo "PasswordAuthentication no" >> /etc/ssh/sshd_config systemctl restart sshd
AIDE(Advanced Intrusion Detection Environment)创建系统文件数据库,定期对比发现被篡改的文件。
bash
dnf install aide -y
编辑配置/etc/aide.conf,选择需要监控的目录(默认已包含/bin, /sbin, /etc等关键路径)。
初始化数据库:
bash
aide --init mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
bash
cat > /etc/cron.daily/aide-check <<EOF #!/bin/bash aide --check | mail -s "AIDE Daily Report" admin@yourdomain.com EOF chmod +x /etc/cron.daily/aide-check
若有文件被篡改,报告中会显示“changed”。结合auditd日志进一步调查。
auditd可记录系统调用、文件访问、用户操作等,用于事后溯源和实时告警。
bash
dnf install audit -y systemctl enable auditd --now
编辑/etc/audit/rules.d/audit.rules:
bash
# 监控/etc/passwd和/etc/shadow的修改 -w /etc/passwd -p wa -k identity -w /etc/shadow -p wa -k identity # 监控sudo执行 -w /usr/bin/sudo -p x -k sudo_exec # 监控SSH配置文件 -w /etc/ssh/sshd_config -p wa -k sshd_config # 记录所有对/var/www/html的写操作 -w /var/www/html -p wa -k web_content
加载规则:
bash
augenrules --load systemctl restart auditd
bash
# 查看所有与identity标签相关的记录 ausearch -k identity # 查看今天所有失败的登录尝试 ausearch -m USER_LOGIN -sv no
可安装swatch或自写脚本监控audit.log并发送邮件。
Fail2ban扫描日志文件,对多次失败的IP进行动态封禁(通过防火墙或iptables)。
bash
dnf install epel-release -y dnf install fail2ban -y
创建本地配置文件/etc/fail2ban/jail.local:
ini
[DEFAULT] bantime = 3600 # 封禁1小时 findtime = 600 # 10分钟内 maxretry = 5 # 失败5次触发 [sshd] enabled = true port = ssh logpath = %(sshd_log)s backend = systemd
若SSH更改了端口,修改port值。
bash
systemctl enable fail2ban --now
bash
fail2ban-client status sshd
bash
fail2ban-client set sshd unbanip 192.168.1.100
将以上检查项整合为每日巡检脚本,输出报告:
bash
#!/bin/bash echo "=== Firewall Rules ===" firewall-cmd --list-all echo -e "\\n=== SELinux Status ===" getenforce echo -e "\\n=== Failed SSH Attempts (last 24h) ===" journalctl _SYSTEMD_UNIT=sshd.service --since "24 hours ago" | grep "Failed password" | wc -l echo -e "\\n=== AIDE Check (last run) ===" tail -1 /var/log/aide/aide.log echo -e "\\n=== Auditd Recent Events ===" ausearch -ts today | head -20
将此脚本加入cron,每天发送给管理员。
Linux安全加固不是一次性的工作,而是持续的过程。记住:没有绝对的安全,只有相对的安全。保持警惕,持续改进。